#include "TimerQueue.h"

#include "EventLoop.h"
#include "Timer.h"
#include "../../base/log/Logging.h"

#include <sys/timerfd.h>

namespace detail {
    /**
     * 创建Linux的timerfd文件描述符
     * @return 返回timerfd文件描述符
     */
    int createTimerfd() {
        int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
                                       TFD_NONBLOCK | TFD_CLOEXEC);
        if (timerfd < 0) {
            LOG_SYSFATAL << "创建时间事件失败";
        }
        return timerfd;
    }

    /**
     * 计算when指向的时间距离现在有多少时间
     * @param when
     * @return
     */
    struct timespec howMuchTimeFromNow(Timestamp when) {
        int64_t microseconds = when.microSecondsSinceEpoch()
                               - Timestamp::now().microSecondsSinceEpoch();
        // 计算when的时间距现在有多久, 时间单位 ms
        if (microseconds < 100) {
            microseconds = 100;
            // 微秒 (ms)
        }
        struct timespec ts;
        ts.tv_sec = static_cast<time_t>(
                microseconds / Timestamp::kMicroSecondsPerSecond);
        // 设置时间类的秒数值
        ts.tv_nsec = static_cast<long>(
                (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
        // 设置时间结构体的ns
        return ts;
    }

    /**
     * 读取时间事件文件描述符, 消除epoll的触发
     * @param timerfd
     * @param now
     */
    void readTimerfd(int timerfd, Timestamp now) {
        uint64_t howmany;
        ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
        LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
        if (n != sizeof howmany) {
            LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
        }
    }

    /**
     * 重新设定Timerfd文件描述符上的时间
     * @param timerfd
     * @param expiration
     */
    void resetTimerfd(int timerfd, Timestamp expiration) {
        // wake up loop by timerfd_settime()
        struct itimerspec newValue;
        struct itimerspec oldValue;
        memZero(&newValue, sizeof newValue);
        memZero(&oldValue, sizeof oldValue);
        newValue.it_value = howMuchTimeFromNow(expiration);
        int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
        if (ret) {
            LOG_SYSERR << "timerfd_settime调用异常";
        }
    }
}

TimerQueue::TimerQueue(EventLoop *loop) :
        loop_(loop),
        timerfd_(detail::createTimerfd()),
        timerfdChannel_(loop, timerfd_),
        timers_(),
        callingExpiredTimers_(false) {
    timerfdChannel_.setReadCallback(
            std::bind(&TimerQueue::handleRead, this));
    // 一直读取调用handleRead, 直到解除
    timerfdChannel_.enableReading();
    // 绑定timerfd上的可读时间
}

TimerQueue::~TimerQueue() {
    timerfdChannel_.disableAll();
    timerfdChannel_.remove();
    ::close(timerfd_);
    // do not remove channel, since we're in EventLoop::dtor();
    for (const Entry &timer : timers_) {
        delete timer.second;
        // 逐个析构对应时间事件
    }
}

TimerId TimerQueue::addTimer(TimerCallback cb, Timestamp when, double interval) {
    Timer *timer = new Timer(std::move(cb), when, interval);
    // 创建事件事件, 并将其添加到事件循环中, interval是设置时间事件触发的间隔, 间隔 <= 0.0就是不重复
    loop_->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer));
    return TimerId(timer, timer->sequence());
}

void TimerQueue::addTimerInLoop(Timer *timer) {
    loop_->assertInLoopThread();
    bool earliestChanged = insert(timer);
    // 添加时间事件
    if (earliestChanged) {
        detail::resetTimerfd(timerfd_, timer->expiration());
        // 添加成功修正对应的文件描述符对应的事件
    }
}

bool TimerQueue::insert(Timer *timer) {
    loop_->assertInLoopThread();
    assert(timers_.size() == activeTimers_.size());
    bool earliestChanged = false;
    Timestamp when = timer->expiration();
    TimerList::iterator it = timers_.begin();
    if (it == timers_.end() || when < it->first) {
        earliestChanged = true;
    }
    {
        std::pair<TimerList::iterator, bool> result
                = timers_.insert(Entry(when, timer));
        assert(result.second);
        (void) result;
    }
    {
        std::pair<ActiveTimerSet::iterator, bool> result
                = activeTimers_.insert(ActiveTimer(timer, timer->sequence()));
        assert(result.second);
        (void) result;
    }

    assert(timers_.size() == activeTimers_.size());
    return earliestChanged;
}

void TimerQueue::cancel(TimerId timerId) {
    loop_->runInLoop(std::bind(&TimerQueue::cancelInLoop, this, timerId));
}

void TimerQueue::cancelInLoop(TimerId timerId) {
    loop_->assertInLoopThread();
    assert(timers_.size() == activeTimers_.size());
    ActiveTimer timer(timerId.timer_, timerId.sequence_);
    ActiveTimerSet::iterator it = activeTimers_.find(timer);

    if (it != activeTimers_.end()) {
        size_t n = timers_.erase(Entry(it->first->expiration(), it->first));
        assert(n == 1);
        (void) n;
        // 这里的(void)n是为了避免编译器报变量未使用警告
        delete it->first;
        activeTimers_.erase(it);
    } else if (callingExpiredTimers_) {
        cancelingTimers_.insert(timer);
        // 将元素增加到移除队列中, 因为此时找不到元素说明是被添加到运行队列中运行了
        // 后续在reset中会进行检查防止将这个待移除的元素重新添加回等待队列中
    }
    assert(timers_.size() == activeTimers_.size());
}

void TimerQueue::handleRead() {
    loop_->assertInLoopThread();
    Timestamp now(Timestamp::now());
    detail::readTimerfd(timerfd_, now);

    std::vector<Entry> expired = getExpired(now);

    callingExpiredTimers_ = true;
    cancelingTimers_.clear();
    // safe to callback outside critical section
    for (const Entry &it : expired) {
        it.second->run();
        // 逐个遍历将时间事件执行
    }
    callingExpiredTimers_ = false;

    reset(expired, now);
}

std::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) {
    assert(timers_.size() == activeTimers_.size());
    std::vector<Entry> expired;
    Entry sentry(now, reinterpret_cast<Timer *>(UINTPTR_MAX));
    // 构造一个查询用的TimerId, 时间为现在, 用于在set中查询
    TimerList::iterator end = timers_.lower_bound(sentry);
    // lower_bound 是set提供的寻找第一个大于等于目标值的元素的函数
    assert(end == timers_.end() || now < end->first);
    std::copy(timers_.begin(), end, back_inserter(expired));
    // 将之前的所有元素都插入到expired列表中, 并移除时间队列中的对应元素
    timers_.erase(timers_.begin(), end);

    for (const Entry &it : expired) {
        ActiveTimer timer(it.second, it.second->sequence());
        size_t n = activeTimers_.erase(timer);
        assert(n == 1);
        (void) n;
    }

    assert(timers_.size() == activeTimers_.size());
    return expired;
}


void TimerQueue::reset(const std::vector<Entry> &expired, Timestamp now) {
    Timestamp nextExpire;

    for (const Entry &it : expired) {
        ActiveTimer timer(it.second, it.second->sequence());
        if (it.second->repeat()
            // 当事件事件需要重复执行
            && cancelingTimers_.find(timer) == cancelingTimers_.end())
            //并且在移除队列中没有这个元素, 才将元素重新设置启动并添加到时间队列中
        {
            it.second->restart(now);
            insert(it.second);
        } else {
            // FIXME move to a free list
            delete it.second; // FIXME: no delete please
        }
    }

    if (!timers_.empty()) {
        nextExpire = timers_.begin()->second->expiration();
    }

    if (nextExpire.valid()) {
        detail::resetTimerfd(timerfd_, nextExpire);
    }
}
